import './img-resize.scss';
import { Events } from './event';
import { Drag } from './drag';
import { Tools } from './tools';
import { Subscription } from 'rxjs';
export class ImgResize {
    protected hiddenStyle: string;
    protected block: HTMLElement;
    protected dot: IDot;
    protected content: HTMLElement;
    protected subs: Subscription[] = [];
    protected dragInstances: Drag[] = [];
    protected defaultSetting: IDefaultSettings = {
        limit: {
            maxWidth: null,
            maxHeight: null,
            minWidth: null,
            minHeight: null,
            maxTop: null,
            maxLeft: null,
            minTop: null,
            minLeft: null
        },
        container: {
            className: '',
            style: {
                'position': 'absolute',
                'height': '70px',
                'width': '140px',
                'border': '1px solid #aaaaaa',
                'top': '0px',
                'left': '0px'
            }
        },
        content: {
            className: '',
            style: {
                position: 'absolute',
                top: '0px',
                left: '0px',
                right: '0px',
                bottom: '0px',
                width: '100%',
                'cursor': 'move'
            }
        },
        dot: {
            common: {
                className: '',
                style: {
                    position: 'absolute',
                    height: '10px',
                    width: '10px',
                    'border-radius': '50%',
                    'background-color': '#494949',
                    'z-index': '10'
                }
            },
            topLeft: {
                className: '',
                style: {
                    cursor: 'move',
                    top: '-5px',
                    left: '-5px'
                }
            },
            topMid: {
                className: '',
                style: {
                    cursor: 'n-resize',
                    top: '-5px',
                    left: 'calc(50% - 5px)'
                }
            },
            topRight: {
                className: '',
                style: {
                    cursor: 'move',
                    top: '-5px',
                    right: '-5px'
                }
            },
            rightMid: {
                className: '',
                style: {
                    cursor: 'e-resize',
                    top: 'calc(50% - 5px)',
                    right: '-5px'
                }
            },
            bottomRight: {
                className: '',
                style: {
                    cursor: 'move',
                    bottom: '-5px',
                    right: '-5px'
                }
            },
            bottomMid: {
                className: '',
                style: {
                    cursor: 'n-resize',
                    bottom: '-5px',
                    left: 'calc(50% - 5px)'
                }
            },
            bottomLeft: {
                className: '',
                style: {
                    cursor: 'move',
                    bottom: '-5px',
                    left: '-5px'
                }
            },
            leftMid: {
                className: '',
                style: {
                    cursor: 'e-resize',
                    top: 'calc(50% - 5px)',
                    left: '-5px'
                }
            }
        }
    }
    constructor(private container: HTMLElement, private option: Partial<IDefaultSettings> = {}) {
        this.init(option);
    }
    /**
     * @description 显示
     * @param option 
     */
    public show(option: Partial<IDefaultSettings> = {}) {
        this.block.getAttribute('style');
        this.block.setAttribute('style', this.hiddenStyle);
    }
    /**
     * @description 隐藏
     */
    public hidden() {
        this.hiddenStyle = this.block.getAttribute('style');
        this.block.setAttribute('style', 'display: none;');
    }
    public getSettings() {
        this.defaultSetting.container = {
            className: this.block.getAttribute('class'),
            style: Tools.styleToObj(this.block.getAttribute('style'))
        }
        this.defaultSetting.content = {
            className: this.content.getAttribute('class'),
            style: Tools.styleToObj(this.content.getAttribute('style'))
        }
        for(let dotname in this.dot) {
            (<any>this.defaultSetting.dot)[dotname] = {
                className: (<any>this.dot)[dotname].getAttribute('class'),
                style: Tools.styleToObj((<any>this.dot)[dotname].getAttribute('style'))
            }
        }
        let referenceObj = this.defaultSetting.dot.topLeft.style;
        let commonStyle: {[key: string]: string|number} = {};
        for(let key in referenceObj) {
            let same = true;
            for(let dotname in <any>this.defaultSetting.dot) {
                if(dotname == 'common') continue;
                if((<any>this.defaultSetting.dot)[dotname].style[key] !== referenceObj[key]) {
                    same = false;
                    break;
                }
            }
            if(same == true) {
                commonStyle[key] = referenceObj[key];
            }
        }
        for(let dotname in <any>this.defaultSetting.dot) {
            if(dotname == 'common') continue;
            for(let key in commonStyle) {
                try {
                    delete (<any>this.defaultSetting.dot)[dotname].style[key];
                } catch (error) {
                    
                }
            }
        }
        this.defaultSetting.dot.common.style = commonStyle;
        return this.defaultSetting;
    }
    public updateSetting(settings: IDefaultSettings) {
        if(settings == undefined || settings == null || Object.prototype.toString.call(settings) != '[object Object]') {
            console.warn('setting error!');
            return;
        }
        this.defaultSetting = Tools.assign(this.defaultSetting, settings);
        this.block.setAttribute('class', this.defaultSetting.container.className);
        this.block.setAttribute('style', Tools.objToStyle(this.defaultSetting.container.style));
        this.content.setAttribute('class', this.defaultSetting.content.className);
        this.content.setAttribute('style', Tools.objToStyle(this.defaultSetting.content.style));
        for(let dotname in this.dot) {
            (<any>this.dot)[dotname].setAttribute('class', this.defaultSetting.dot.common.className + ' ' + (<any>this.defaultSetting.dot)[dotname].className);
            (<any>this.dot)[dotname].setAttribute('style', Tools.objToStyle(Tools.combineObj(this.defaultSetting.dot.common.style, (<any>this.defaultSetting.dot)[dotname].style)));
        }
    }
    private init(option: Partial<IDefaultSettings> = {}) {
        this.defaultSetting = Tools.assign(this.defaultSetting, option)
        this.createContainer();
        this.createDot();
        this.createContent();
    }
    private createContainer() {
        this.block = Tools.createDom('div', this.defaultSetting.container.style, {'class': this.defaultSetting.container.className});
        this.container.appendChild(this.block);
    }
    private createDot() {
        this.dot = <any>{};
        for(let name of ['topLeft', 'topMid', 'topRight', 'rightMid', 'bottomRight', 'bottomMid', 'bottomLeft', 'leftMid']) {
            (<any>this.dot)[name] = Tools.createDom(
                'div', 
                Tools.combineObj(this.defaultSetting.dot.common.style, (<any>this.defaultSetting.dot)[name].style), 
                {
                    'class': this.defaultSetting.dot.common.className + ' ' + (<any>this.defaultSetting.dot)[name].className
                }
            );
            this.block.appendChild((<any>this.dot)[name]);
        }
        let fixPosition = (style: {top?: number, left?: number, width?: number, height?: number}) => {
            // if(style.top < this.defaultSetting.limit.minTop) {
            //     style.top = this.defaultSetting.limit.minTop;
            // }
            // if(style.top + style.height > this.defaultSetting.limit.maxTop) {
            //     style.height = this.defaultSetting.limit.maxTop - style.height;
            // }
            return style;
        }
        this.createSub(this.dot.topLeft, () => {return this.block;},
            (style, option, currentStyle) => {
                if(this.defaultSetting.limit.minTop != null && style.top + option.y < this.defaultSetting.limit.minTop) {
                    style.top = this.defaultSetting.limit.minTop;
                    style.height = currentStyle.height;
                }else if (this.defaultSetting.limit.maxTop != null && style.top + option.y > this.defaultSetting.limit.maxTop){
                    style.top = this.defaultSetting.limit.maxTop;
                    style.height = currentStyle.height;
                }else{
                    style.top = style.top + option.y;
                    if(style.height - option.y > this.defaultSetting.limit.maxHeight) {
                        style.height = this.defaultSetting.limit.maxHeight;
                        style.top = currentStyle.top;
                    } else if (style.height - option.y < this.defaultSetting.limit.minHeight) {
                        style.height = this.defaultSetting.limit.minHeight;
                        style.top = currentStyle.top;
                    } else {
                      style.height = style.height - option.y;  
                    }  
                }
                if(this.defaultSetting.limit.minLeft != null && style.left + option.x < this.defaultSetting.limit.minLeft) {
                    style.left = this.defaultSetting.limit.minLeft;
                    style.width = currentStyle.width;
                }else if (this.defaultSetting.limit.maxLeft != null && style.left + option.x > this.defaultSetting.limit.maxLeft){
                    style.left = this.defaultSetting.limit.maxLeft;
                    style.width = currentStyle.width;
                }else{
                    if(style.width - option.x > this.defaultSetting.limit.maxWidth) {
                        style.width = this.defaultSetting.limit.maxWidth;
                        style.left = currentStyle.left;
                    }else if(style.width - option.x < this.defaultSetting.limit.minWidth) {
                        style.width = this.defaultSetting.limit.minWidth;
                        style.left = currentStyle.left;
                    }else{
                        style.width = style.width - option.x;
                        style.left = style.left + option.x;
                    }
                }
                return style;
            }
        );
        this.createSub(this.dot.topMid, () => {return this.block;},
            (style, option, currentStyle) => {
                if(this.defaultSetting.limit.minTop != null && style.top + option.y < this.defaultSetting.limit.minTop) {
                    style.top = this.defaultSetting.limit.minTop;
                    style.height = currentStyle.height;
                }else if (this.defaultSetting.limit.maxTop != null && style.top + option.y > this.defaultSetting.limit.maxTop){
                    style.top = this.defaultSetting.limit.maxTop;
                    style.height = currentStyle.height;
                }else{
                    style.top = style.top + option.y;
                    if(style.height - option.y > this.defaultSetting.limit.maxHeight) {
                        style.height = this.defaultSetting.limit.maxHeight;
                        style.top = currentStyle.top;
                    } else if (style.height - option.y < this.defaultSetting.limit.minHeight) {
                        style.height = this.defaultSetting.limit.minHeight;
                        style.top = currentStyle.top;
                    } else {
                      style.height = style.height - option.y;  
                    }  
                }
                return style;
            }
        );
        this.createSub(this.dot.topRight, () => {return this.block;},
            (style, option, currentStyle) => {
                if(this.defaultSetting.limit.minTop != null && style.top + option.y < this.defaultSetting.limit.minTop) {
                    style.top = this.defaultSetting.limit.minTop;
                    style.height = currentStyle.height;
                }else if (this.defaultSetting.limit.maxTop != null && style.top + option.y > this.defaultSetting.limit.maxTop){
                    style.top = this.defaultSetting.limit.maxTop;
                    style.height = currentStyle.height;
                }else{
                    style.top = style.top + option.y;
                    if(style.height - option.y > this.defaultSetting.limit.maxHeight) {
                        style.height = this.defaultSetting.limit.maxHeight;
                        style.top = currentStyle.top;
                    } else if (style.height - option.y < this.defaultSetting.limit.minHeight) {
                        style.height = this.defaultSetting.limit.minHeight;
                        style.top = currentStyle.top;
                    } else {
                      style.height = style.height - option.y;  
                    }  
                }
                let compareWidth = style.width + option.x;
                if(this.defaultSetting.limit.maxLeft != null && compareWidth + style.left > this.defaultSetting.limit.maxLeft) {
                    if(this.defaultSetting.limit.maxLeft + compareWidth > this.defaultSetting.limit.maxWidth) {
                        style.width = this.defaultSetting.limit.maxLeft - style.left;
                    }else{
                        style.width = this.defaultSetting.limit.maxWidth;
                    }
                }else if(compareWidth < this.defaultSetting.limit.minWidth) {
                    style.width = this.defaultSetting.limit.minWidth;
                }else{
                    style.width = compareWidth;
                }
                return fixPosition(style);
            }
        );
        this.createSub(this.dot.rightMid, () => {return this.block;},
            (style, option, currentStyle) => {
                let compareWidth = style.width + option.x;
                if(this.defaultSetting.limit.maxLeft != null && compareWidth + style.left > this.defaultSetting.limit.maxLeft) {
                    if(this.defaultSetting.limit.maxLeft + compareWidth > this.defaultSetting.limit.maxWidth) {
                        style.width = this.defaultSetting.limit.maxLeft - style.left;
                    }else{
                        style.width = this.defaultSetting.limit.maxWidth;
                    }
                }else if(compareWidth < this.defaultSetting.limit.minWidth) {
                    style.width = this.defaultSetting.limit.minWidth;
                }else{
                    style.width = compareWidth;
                }
                return style;
            }
        );
        this.createSub(this.dot.bottomRight, () => {return this.block;},
            (style, option, currentStyle) => {
                // style.width = style.width + option.x;
                // style.height = style.height + option.y;
                let compareWidth = style.width + option.x;
                if(this.defaultSetting.limit.maxLeft != null && compareWidth + style.left > this.defaultSetting.limit.maxLeft) {
                    if(this.defaultSetting.limit.maxLeft + compareWidth > this.defaultSetting.limit.maxWidth) {
                        style.width = this.defaultSetting.limit.maxLeft - style.left;
                    }else{
                        style.width = this.defaultSetting.limit.maxWidth;
                    }
                }else if(compareWidth < this.defaultSetting.limit.minWidth) {
                    style.width = this.defaultSetting.limit.minWidth;
                }else{
                    style.width = compareWidth;
                }
                let compareHeight = style.height + option.y;
                if(this.defaultSetting.limit.maxTop != null && compareHeight + style.top > this.defaultSetting.limit.maxTop) {
                    if(this.defaultSetting.limit.maxTop + compareHeight > this.defaultSetting.limit.maxHeight) {
                        style.height = this.defaultSetting.limit.maxTop - style.top;
                    }else{
                        style.height = this.defaultSetting.limit.maxHeight;
                    }
                }else if(compareHeight < this.defaultSetting.limit.minHeight) {
                    style.height = this.defaultSetting.limit.minHeight;
                }else{
                    style.height = compareHeight;
                }
                return fixPosition(style);
            }
        );
        this.createSub(this.dot.bottomMid, () => {return this.block;},
            (style, option) => {
                let compareHeight = style.height + option.y;
                if(this.defaultSetting.limit.maxTop != null && compareHeight + style.top > this.defaultSetting.limit.maxTop) {
                    if(this.defaultSetting.limit.maxTop + compareHeight > this.defaultSetting.limit.maxHeight) {
                        style.height = this.defaultSetting.limit.maxTop - style.top;
                    }else{
                        style.height = this.defaultSetting.limit.maxHeight;
                    }
                }else if(compareHeight < this.defaultSetting.limit.minHeight) {
                    style.height = this.defaultSetting.limit.minHeight;
                }else{
                    style.height = compareHeight;
                }
                return style;
            }
        );
        this.createSub(this.dot.bottomLeft, () => {return this.block;},
            (style, option, currentStyle) => {
                let compareHeight = style.height + option.y;
                if(this.defaultSetting.limit.maxTop != null && compareHeight + style.top > this.defaultSetting.limit.maxTop) {
                    if(this.defaultSetting.limit.maxTop + compareHeight > this.defaultSetting.limit.maxHeight) {
                        style.height = this.defaultSetting.limit.maxTop - style.top;
                    }else{
                        style.height = this.defaultSetting.limit.maxHeight;
                    }
                }else if(compareHeight < this.defaultSetting.limit.minHeight) {
                    style.height = this.defaultSetting.limit.minHeight;
                }else{
                    style.height = compareHeight;
                }
                if(this.defaultSetting.limit.minLeft != null && style.left + option.x < this.defaultSetting.limit.minLeft) {
                    style.left = this.defaultSetting.limit.minLeft;
                    style.width = currentStyle.width;
                }else if (this.defaultSetting.limit.maxLeft != null && style.left + option.x > this.defaultSetting.limit.maxLeft){
                    style.left = this.defaultSetting.limit.maxLeft;
                    style.width = currentStyle.width;
                }else{
                    if(style.width - option.x > this.defaultSetting.limit.maxWidth) {
                        style.width = this.defaultSetting.limit.maxWidth;
                        style.left = currentStyle.left;
                    }else if(style.width - option.x < this.defaultSetting.limit.minWidth) {
                        style.width = this.defaultSetting.limit.minWidth;
                        style.left = currentStyle.left;
                    }else{
                        style.width = style.width - option.x;
                        style.left = style.left + option.x;
                    }
                }
                return fixPosition(style);
            }
        );
        this.createSub(this.dot.leftMid, () => {return this.block;},
            (style, option,currentStyle) => {
                if(this.defaultSetting.limit.minLeft != null && style.left + option.x < this.defaultSetting.limit.minLeft) {
                    style.left = this.defaultSetting.limit.minLeft;
                    style.width = currentStyle.width;
                }else if (this.defaultSetting.limit.maxLeft != null && style.left + option.x > this.defaultSetting.limit.maxLeft){
                    style.left = style.left - (this.defaultSetting.limit.maxWidth - style.width);
                    style.width = this.defaultSetting.limit.maxWidth;
                }else{
                    if(style.width - option.x > this.defaultSetting.limit.maxWidth) {
                        style.left = style.left - (this.defaultSetting.limit.maxWidth - style.width);
                        style.width = this.defaultSetting.limit.maxWidth;
                        // style.left = currentStyle.left;
                    }else if(style.width - option.x < this.defaultSetting.limit.minWidth) {
                        style.width = this.defaultSetting.limit.minWidth;
                        style.left = currentStyle.left;
                    }else{
                        style.width = style.width - option.x;
                        style.left = style.left + option.x;
                    }
                }
                return fixPosition(style);
            }
        );        
    }
    private boundray(val: number, max: number | null, min: number | null) {
        if(val > max && max !== null) {
            return max;
        }
        if(val < min && min !== null) {
            return min;
        }
        return val;
    }
    private createContent() {
        this.content = Tools.createDom('div', this.defaultSetting.content.style, {'class': this.defaultSetting.content.className});
        this.block.appendChild(this.content);
        this.createSub(
            this.content,
            () => {return this.block;},
            (style, option) => {
                if(style.top + option.y < this.defaultSetting.limit.minTop) {
                    style.top = this.defaultSetting.limit.minTop;
                }else if(style.top + option.y + style.height > this.defaultSetting.limit.maxTop) {
                    style.top = this.defaultSetting.limit.maxTop - style.height;
                }else{
                    style.top = style.top + option.y;
                }
                if(style.left + option.x < this.defaultSetting.limit.minLeft) {
                    style.left = this.defaultSetting.limit.minLeft;
                } else if(style.left + option.x + style.width > this.defaultSetting.limit.maxLeft) {
                    style.left = this.defaultSetting.limit.maxLeft - style.width;
                } else {
                    style.left = style.left + option.x;
                }
                return style;
            }
        );
    }
    private createSub(ele: HTMLElement, setEle: {(): HTMLElement}, setStyle: {(styleObj: IPostionStyleNum, option: {x: number, y: number}, currentStyle?: IPostionStyleNum): IPostionStyleNum}) {
        let contentDrag = new Drag(ele, setEle);
        let sub = contentDrag.move.subscribe(res => {
            let style: IPostionStyle =  Tools.styleToObj(res.startEle.getAttribute('style'));
            let attrs = ['top', 'left', 'bottom', 'right', 'width', 'height'];
            let numStyle = Tools.styleAttrPxToNum<IPostionStyleNum>(style, attrs);
            let currentStyle = Tools.styleAttrPxToNum<IPostionStyleNum>(Tools.styleToObj(this.block.getAttribute('style')), attrs);
            let newStyle = setStyle(numStyle, {x: res.position.x, y: res.position.y}, currentStyle);
            if(this.defaultSetting.limit.maxHeight != null && newStyle.height > this.defaultSetting.limit.maxHeight) {
                newStyle.height = this.defaultSetting.limit.maxHeight;
            }
            if(this.defaultSetting.limit.minHeight != null  && newStyle.height < this.defaultSetting.limit.minHeight) {
                newStyle.height = this.defaultSetting.limit.minHeight;
            }
            if(this.defaultSetting.limit.maxWidth != null && newStyle.width > this.defaultSetting.limit.maxWidth) {
                newStyle.width = this.defaultSetting.limit.maxWidth;
            }
            if(this.defaultSetting.limit.minWidth != null && newStyle.width < this.defaultSetting.limit.minWidth) {
                newStyle.width = this.defaultSetting.limit.minWidth;
            }
            this.block.setAttribute('style', Tools.objToStyle(Tools.styleAttrNumToPx(newStyle, attrs)));
        });
        this.subs.push(sub);
        this.dragInstances.push(contentDrag);
    }
    /**
     * @description 销毁
     */
    public destroy() {
        for(let itemSub of this.subs) {
            try {
                itemSub.unsubscribe();
            } catch (error) {
                
            }
        }
        this.block.remove();
    }
}
interface IPostionStyle {
    top?: string, 
    left?: string, 
    right?: string, 
    bottom?: string, 
    height?: string,
    width?: string
    [key: string]: any
}
interface IPostionStyleNum {
    top?: number, 
    left?: number, 
    right?: number, 
    bottom?: number, 
    height?: number,
    width?: number
    [key: string]: any
}
interface IOption {
    height?: number;
    width?: number;
    top?: number;
    left?: number;
}
interface IDot {
    topLeft?: HTMLElement;
    topMid?: HTMLElement;
    topRight?: HTMLElement;
    rightMid?: HTMLElement;
    bottomRight?: HTMLElement;
    bottomMid?: HTMLElement;
    bottomLeft?: HTMLElement;
    leftMid?: HTMLElement;
}
export interface IDefaultSettings {
    limit?: {
        maxWidth?: number|null,
        maxHeight?: number|null,
        minWidth?: number|null,
        minHeight?: number|null,
        maxTop?: number|null,
        maxLeft?: number|null,
        minTop?: number|null,
        minLeft?: number|null
    }
    content?: IStyleSetting,
    container?: IStyleSetting;
    dot?: {
        common?: IStyleSetting;
        topLeft?: IStyleSetting;
        topMid?: IStyleSetting,
        topRight?: IStyleSetting,
        rightMid?: IStyleSetting,
        bottomRight?: IStyleSetting,
        bottomMid?: IStyleSetting,
        bottomLeft?: IStyleSetting,
        leftMid?: IStyleSetting
    }
}
interface IStyleSetting {
    className?: string; 
    style?: {
        height?: string;
        width?: string;
        top?: string;
        left?: string;
        right?: string;
        bottom?: string;
        [key: string]: string|number
    }
}